﻿using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Odyssey.Application.Implementations
{
    public class OdysseyConsoleHost : IApplicationHost
    {
        private readonly IServiceCollection _builderServiceCollection;
        private readonly IServiceProvider _builderServicesProvider;
        private readonly ManualResetEventSlim _manualResetEventSlim;
        private readonly IStartup _startup;

        private IServiceProvider _hostServiceProvider;
        private IApplicationLifetime _applicationLifetime;
        private bool _exitedGracefully;
        private bool _initialized;

        public OdysseyConsoleHost(IServiceCollection builderServiceCollection, IServiceProvider builderServiceProvider)
        {
            _builderServiceCollection = builderServiceCollection;
            _builderServicesProvider = builderServiceProvider;
            _manualResetEventSlim = new ManualResetEventSlim();
            _startup = builderServiceProvider.GetService<IStartup>();
            _initialized = false;
        }

        public IServiceProvider Services {
            get {
                return _hostServiceProvider;
            }
        }

        public void Dispose()
        {
            AppDomain.CurrentDomain.ProcessExit -= ProcessExit;
            Console.CancelKeyPress -= CancelKeyPress;
        }




        public Task StartAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            Initialize((applicationLifetime) =>
            {
                _applicationLifetime.ApplicationStarted.Register(() =>
                {
                    Console.WriteLine("应用已开启，请键入Ctrl+C退出");
                });
            });

            AppDomain.CurrentDomain.ProcessExit += ProcessExit;
            Console.CancelKeyPress += CancelKeyPress;
            _applicationLifetime.StartNotify();
            _manualResetEventSlim.Wait();
            return Task.CompletedTask;
        }

        public Task StopAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            _applicationLifetime.StopNotify();
            return Task.CompletedTask;
        }

        internal void SetExitedGracefully()
        {
            _exitedGracefully = true;
        }

        private void Initialize(Action<IApplicationLifetime> initializeAction)
        {
            if (!_initialized)
            {
                _hostServiceProvider = _startup?.ConfigureServices(_builderServiceCollection);
                if (_hostServiceProvider == null)
                {
                    _hostServiceProvider = _builderServiceCollection.BuildServiceProvider();
                }

                _applicationLifetime = _hostServiceProvider.GetRequiredService<IApplicationLifetime>();

                initializeAction(_applicationLifetime);
                _startup?.Configure(_hostServiceProvider);

            }
        }

        private void ProcessExit(object sender, EventArgs eventArgs)
        {
            Shutdown();
            if (_exitedGracefully)
            {
                Environment.ExitCode = 0;
            }
        }

        private void CancelKeyPress(object sender, ConsoleCancelEventArgs eventArgs)
        {
            Shutdown();
            eventArgs.Cancel = true;
        }

        private void Shutdown()
        {
            _applicationLifetime.StopNotify();
            _manualResetEventSlim.Set();
        }
    }
}
